# -*- coding: utf-8 -*-
# author  :Pengyz
# date    :2022-08-01


# 交互式Dubois and Prade 算子

# 若要修改参数x，可在调用时传入参数self.x

import os
from Utilities.AutoGetOperator.selectPackage import get_func

Operator_IVQ_ROFS=get_func(r'Operators/OperationOperators/OperatorIVQROF.py','Operator_IVQ_ROFS')


class ImDuboisAndPrade(Operator_IVQ_ROFS):

    # 若要修改参数x，可在调用时传入参数self.x

    def add(self, a, b, q=0):
        """
        交互式DuboisAndPrade加法运算
        :param a:
        :param b:
        :param q:
        :param x: 参数
        :return:
        """

        if q <= 0:
            q = self.q
        if self.x > 1 or self.x < 0:
            x = 0.5
        else:
            x = self.x

        u1 = (1 - ((1 - a[0][0] ** q) * (1 - b[0][0] ** q)) / (max(1 - a[0][0] ** q, 1 - b[0][0] ** q, x))) ** (1 / q)
        u2 = (1 - ((1 - a[0][1] ** q) * (1 - b[0][1] ** q)) / (max(1 - a[0][1] ** q, 1 - b[0][1] ** q, x))) ** (1 / q)
        v1 = (((1 - a[0][0] ** q) * (1 - b[0][0] ** q) - (1 - a[0][0] ** q - a[1][0] ** q) * (
                    1 - b[0][0] ** q - b[1][0] ** q)) / (max(1 - a[0][0] ** q, 1 - b[0][0] ** q, x))) ** (1 / q)
        v2 = (((1 - a[0][1] ** q) * (1 - b[0][1] ** q) - (1 - a[0][1] ** q - a[1][1] ** q) * (
                    1 - b[0][1] ** q - b[1][1] ** q)) / (max(1 - a[0][1] ** q, 1 - b[0][1] ** q, x))) ** (1 / q)

        return([u1,u2],[v1,v2])

    def multi(self, a, b, q=0):
        """
        交互式DuboisAndPrade乘法运算
        :param a:
        :param b:
        :param q:
        :param x: 参数
        :return:
        """

        if q <= 0:
            q = self.q
        if self.x > 1 or self.x < 0:
            x = 0.5
        else:
            x = self.x

        u1 = (((1 - a[1][0] ** q) * (1 - b[1][0] ** q) - (1 - a[0][0] ** q - a[1][0] ** q) * (
                    1 - b[0][0] ** q - b[1][0] ** q)) / (max(1 - a[1][0] ** q, 1 - b[1][0] ** q, x))) ** (1 / q)
        u2 = (((1 - a[1][1] ** q) * (1 - b[1][1] ** q) - (1 - a[0][1] ** q - a[1][1] ** q) * (
                    1 - b[0][1] ** q - b[1][1] ** q)) / (max(1 - a[1][1] ** q, 1 - b[1][1] ** q, x))) ** (1 / q)
        v1 = (1 - ((1 - a[1][0] ** q) * (1 - b[1][0] ** q)) / (max(1 - a[1][0] ** q, 1 - b[1][0] ** q, x))) ** (1 / q)
        v2 = (1 - ((1 - a[1][1] ** q) * (1 - b[1][1] ** q)) / (max(1 - a[1][1] ** q, 1 - b[1][1] ** q, x))) ** (1 / q)

        return ([u1, u2], [v1, v2])

    def kmulti(self, a, k, q=0):
        """
        交互式DuboisAndPrade数乘运算
        :param a:
        :param k:
        :param q:
        :param x:
        :return:
        """

        if q <= 0:
            q = self.q
        if self.x > 1 or self.x < 0:
            x = 0.5
        else:
            x = self.x

        u1 = (1 - ((1 - a[0][0] ** q) ** k) / ((max(1 - a[0][0] ** q, x)) ** (k - 1))) ** (1 / q)
        u2 = (1 - ((1 - a[0][1] ** q) ** k) / ((max(1 - a[0][1] ** q, x)) ** (k - 1))) ** (1 / q)
        v1 = (((1 - a[0][0] ** q) ** k - (1 - a[0][0] ** q - a[1][0] ** q) ** k) / ((max(1 - a[0][0] ** q, x)) ** (k - 1))) ** (1 / q)
        v2 = (((1 - a[0][1] ** q) ** k - (1 - a[0][1] ** q - a[1][1] ** q) ** k) / ((max(1 - a[0][1] ** q, x)) ** (k - 1))) ** (1 / q)

        return ([u1, u2], [v1, v2])

    def pow(self, a, k, q=0):
        """
        交互式DuboisAndPrade幂运算
        :param a:
        :param k:
        :param q:
        :param x:
        :return:
        """

        if q <= 0:
            q = self.q
        if self.x > 1 or self.x < 0:
            x = 0.5
        else:
            x = self.x

        u1 = (((1 - a[1][0] ** q) ** k - (1 - a[0][0] ** q - a[1][0] ** q) ** k) / (max(1 - a[1][0] ** q, x)) ** (k - 1)) ** (1 / q)
        u2 = (((1 - a[1][1] ** q) ** k - (1 - a[0][1] ** q - a[1][1] ** q) ** k) / (max(1 - a[1][1] ** q, x)) ** (k - 1)) ** (1 / q)
        v1 = (1 - ((1 - a[1][0] ** q) ** k) / ((max(1 - a[1][0] ** q, x)) ** (k - 1))) ** (1 / q)
        v2 = (1 - ((1 - a[1][1] ** q) ** k) / ((max(1 - a[1][1] ** q, x)) ** (k - 1))) ** (1 / q)

        return ([u1, u2], [v1, v2])

# 若要修改参数x，可在调用时传入参数self.x

class ImDuboisAndPradeA(ImDuboisAndPrade):

    def getResult(self):
        '''
        function：基础的算数平均公式
        :return: AA公式计算的结果
        '''

        result = self.data_list[0]
        for i in range(1, len(self.data_list)):
            result = self.add(result, self.data_list[i])
        result = self.kmulti(result, 1 / len(self.data_list))

        return result


class ImDuboisAndPradeGA(ImDuboisAndPrade):

    def getResult(self):
        data_list = self.data_list
        res = data_list[0]
        n = len(data_list)
        for idx in range(n):
            if idx == 0:
                continue
            res = self.multi(res, data_list[idx])
        res = self.pow(res, 1 / n)

        return res


class ImDuboisAndPradeWA(ImDuboisAndPrade):

    def getResult(self):
        data_list = self.data_list
        weight_list = self.weight_list
        q = self.q
        res = self.kmulti(data_list[0], weight_list[0])
        n = len(weight_list)

        for idx in range(n):
            if idx == 0:
                continue
            res = self.add(res, self.kmulti(data_list[idx], weight_list[idx], q))
        return res


class ImDuboisAndPradeWGA(ImDuboisAndPrade):

    def getResult(self):
        data_list = self.data_list
        weight_list = self.weight_list
        q = self.q
        n = len(data_list)
        res = self.pow(data_list[0], weight_list[0])
        for idx in range(n):
            if idx == 0:
                continue
            res = self.multi(res, self.pow(data_list[idx], weight_list[idx], q))
        return res


class ImDuboisAndPradeOWA(ImDuboisAndPrade):

    def getResult(self):
        data_list = self.sortdata()
        weight_list = self.weight_list
        q = self.q
        n = len(data_list)
        print(self.x)
        res = self.kmulti(data_list[0], weight_list[0])
        for idx in range(n):
            if idx == 0:
                continue
            res = self.add(res, self.kmulti(data_list[idx], weight_list[idx], q))
        return res


# 验证算子
if __name__ == '__main__':
    data_list = [([0.31, 0.24], [0.73, 0.72]), ([0.97, 0.12], [0.12, 0.05]), ([0.8, 0.52], [0.73, 0.15]), ([0.91, 0.49], [0.42, 0.47]), ([0.95, 0.06], [0.19, 0.1])]
    # data_list1 = [([0.91, 0.49], [0.42, 0.47]), ([0.97, 0.12], [0.12, 0.05]), ([0.31, 0.24], [0.73, 0.72]), ([0.95, 0.06], [0.19, 0.1]), ([0.8, 0.52], [0.73, 0.15])]
    # data_list = [([0.31, 0.24], [0.73, 0.72]),([0.31, 0.24], [0.73, 0.72]),([0.31, 0.24], [0.73, 0.72]), ([0.31, 0.24], [0.73, 0.72]), ([0.31, 0.24], [0.73, 0.72])]
    data_list1 = [([0.32, 0.25], [0.72, 0.71]), ([0.98, 0.13], [0.11, 0.04]), ([0.81, 0.53], [0.72, 0.14]), ([0.92, 0.5], [0.41, 0.46]), ([0.96, 0.07], [0.18, 0.09])]
    weight_list = [0.1, 0.2, 0.3, 0.1, 0.3]
    # Pa = ImDuboisAndPradeA(data_list)
    # Pa = ImDuboisAndPradeGA(data_list)
    # Pa = ImDuboisAndPradeWA(data_list,weight_list)
    # Pa = ImDuboisAndPradeWGA(data_list,weight_list)
    Pa = ImDuboisAndPradeOWA(data_list,weight_list)
    print(Pa.getResult())
    # Pa1 = ImDuboisAndPradeA(data_list1)
    # Pa1 = ImDuboisAndPradeGA(data_list1)
    # Pa1 = ImDuboisAndPradeWA(data_list1,weight_list)
    # Pa1 = ImDuboisAndPradeWGA(data_list1,weight_list)
    Pa1 = ImDuboisAndPradeOWA(data_list1,weight_list)
    print(Pa1.getResult())
